#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "table.h"
#include "field.h"

static int html_tag_is(char *ptr, char *tag)
{
    if (ptr[0] != '<')
        return 0;
    return (strncmp(ptr+1, tag, strlen(tag)) == 0);
}

/*
static char *html_tag_get_start(char *ptr, char *tag)
{
    while(((ptr = strchr(ptr, '<')) != NULL)
            && (strncmp(ptr+1, tag, strlen(tag)) != 0) ) {
        ptr++;
    }
    return ptr;
}
static char *html_tag_get_end(char *ptr, char *tag)
{
    while((ptr = strchr(ptr, '<')) != NULL) {
        if ((ptr[1] == '/')
                && (strncmp(ptr+2, tag, strlen(tag)) == 0)) {
            break;
        }
        ptr++;
    }
    return ptr;
}

static char *skip_spaces(char *ptr)
{
    while (isspace(*ptr)) {
        ++ptr;
    }
    return ptr;
}

static char *skip_char(char *str, char *reject)
{
    size_t off;
    off = strspn(str, reject);
    return (str+off);
}

static char *tag_get_tag_attr(char *tag, char *attr, char *buf)
{
    char *pos = tag;
    char *end = strchr(tag, '>');
    char *attrname = NULL;
    char *attrvalue = NULL;
    char quot = 0;

    if (end) {
        *end = '\0';
    }
    if (pos < end) {
        attrname = strstr(tag, attr);
        if (attrname) {
            attrvalue = strchr(attrname, '=')+1;
            attrvalue = skip_spaces(attrvalue);
            quot = strspn(attrvalue, "\"\'");
            attrvalue += quot;
            quot = strcspn(attrvalue, "\'\" ");
            snprintf(buf, quot+1, "%s", attrvalue);
        }
    }
    if (end) {
        *end = '>';
    }
    return attrvalue;
}


static char *token_strdup(char *str, char *end)
{
    size_t end_pos = 0;
    char *token = NULL;
    str = skip_spaces(str);
    end_pos = strcspn(str, end);
    if (end_pos) {
        token = malloc(end_pos+1);
        memcpy(token, str, end_pos);
        token[end_pos] = '\0';
    }
    return token;
}
*/

void table_show(table_t *table)
{
    static int tab = 0;
    int i;
    while(table) {
        printf("----------%s-----------\n",
                table->caption?table->caption:"");
        struct tr *trp = table->trs;
        while(trp)
        {
            struct td *tdp = trp->tds;
            for(i=0; i < tab; i++) {
                printf("\t");
            }
            while(tdp){
                printf(":%s", tdp->text ? tdp->text : "\n");
                if (tdp->table) {
                    tab++;
                    table_show(tdp->table);
                    tab--;
                }
                tdp = tdp->next;
            }
            printf("\n");
            trp = trp->next;
        }
        table = table->next;
    }
}

/*
static char *strdup(char *str)
{
    char *s;
    s = malloc(strlen(str)+1);
    strcpy(s, str);
    return s;
}
*/

struct field *table_to_fields(struct table *t)
{
    field_t *f = NULL, *fields = NULL;
    field_t *f_tr = NULL, *f_td = NULL;
    while(t) {
        struct tr *trp = t->trs;
        f = field_new();
        if (f->name) {
            f->name = strdup(t->caption);
        }
        if (fields) {
            field_append(fields, f);
        } else {
            fields = f;
        }
        while(trp)
        {
            struct td *tdp = trp->tds;
            int col = 0;
            f_tr = field_new();
            field_add_child(f, f_tr);
            while(tdp){
                if (tdp->table) {
                    f_td = table_to_fields(tdp->table);
                    field_add_child(f_tr, f_td);
                }
                switch(col) {
                    case 0://name
                        f_tr->name = strdup(tdp->text);
                        break;
                    case 1://type
                        if (tdp->table) {
                            f_tr->type = FIELD_TYPE_STRUCT;
                        } else {
                            if (strncmp(tdp->text, "uint", strlen("uint")) == 0) {
                                f_tr->type = FIELD_TYPE_UINT;
                                sscanf(tdp->text+strlen("uint"),"%d", &f_tr->count);
                            } else if (strncmp(tdp->text, "int", strlen("int")) == 0) {
                                f_tr->type = FIELD_TYPE_INT;
                                sscanf(tdp->text+strlen("int"),"%d", &f_tr->count);
                            } else if (strncmp(tdp->text, "@", 1) == 0) {
                                f_tr->type = FIELD_TYPE_DENPENDENCY;
                                f_tr->desc.dp.depend_name = strdup(tdp->text+1);
                            }
                        }
                        break;
                    case 2://constraint
                        break;
                }
                col++;
                tdp = tdp->next;
            }
            trp = trp->next;
        }
        t = t->next;
    }
    return fields;
}

static char *skip_comment(char *html)
{
    char *cp = html;
    if (html_tag_is(html, "!--")) {
        cp += 4;
        while (!(cp[-2] == '-' && cp[-1] == '-' && cp[0] == '>')) {
                ++cp;
        }
        if (*cp) {
            ++cp;
        }
        memset(html, ' ', cp - html);
    }
    return cp;
}

struct table *table_get_from_html(char *html)
{
    enum {
        step_get_left,
        step_get_right
    };
    struct table *table = NULL,
                 *table_tail = NULL,
                 *t = NULL;
    struct tr *tr = NULL;
    struct td *td = NULL;
    int step = step_get_left;
    int in_table = 0;
    char ch = 0;
    char *sp = NULL;
    char *cp = html;
    char *td_text = NULL;
    char *caption = NULL;

    for (cp = html; *cp; ++cp) {

        if (step == step_get_left && *cp == '<' && cp[1] != '<') {
            if (html_tag_is(cp, "!--")) {
                cp = skip_comment(cp);
                continue;
            }
            sp = cp;
            step = step_get_right;

        } else if (step == step_get_right && *cp == '>' && cp[1] != '>') {
            if (!sp) {
                step = step_get_left;
                continue;
            }

            if (html_tag_is(sp, "table")) {
                in_table++;
                t = calloc(1, sizeof(table_t));
                if (!table)  { /* 第一张表 */
                    table = t;
                    table_tail = t;
                } else { /* 添加到表尾 push table */
                    table_tail->next = t;
                    t->prev = table_tail;
                    t->next = NULL;
                    table_tail = t;
                }

                if (in_table > 1) { /* 为内嵌表 */
                    if (!td->table) {
                        td->table = t;
                    } else {
                        struct table *tail = td->table;
                        while (tail->next) {
                            tail = tail->next;
                        }
                        tail->next = t;
                    }
                }
            } else if (html_tag_is(sp, "/table")) {

                /* 为内嵌表则从表尾删除 pop table */
                if (in_table > 1 && t && t->prev) {
                    t = t->prev;
                    t->next = NULL;
                    table_tail = t;
                    tr = t->tail;
                    td = tr->tail;
                }
                in_table--;
            } else if (html_tag_is(sp, "caption")){
                caption = cp + 1;
            } else if (html_tag_is(sp, "/caption")){
                ch = *sp;
                *sp = '\0';
                /* strdup not ansi c*/
                if (caption) {
                    t->caption = strdup(caption);
                }
                *sp = ch;
            } else if (html_tag_is(sp, "tr")){
                tr = calloc(1, sizeof(tr_t));
                if(t->trs) {
                    t->tail->next = tr;
                    tr->prev = t->tail;
                    tr->next = NULL;
                    t->tail = tr;
                } else {
                    t->trs = tr;
                    t->tail = tr;
                }
            } else if (html_tag_is(sp, "/tr")){
            } else if (html_tag_is(sp, "td") || html_tag_is(sp, "th")) {
                td = calloc(1, sizeof(td_t));
                td_text = cp + 1;
                if(tr && tr->tds) {
                    tr->tail->next = td;
                    td->prev = tr->tail;
                    td->next = NULL;
                    tr->tail = td;
                } else {
                    tr->tds = td;
                    tr->tail = td;
                }
            } else if (html_tag_is(sp, "/td") || html_tag_is(sp, "/th")) {
                *sp = '\0';
                if (td_text) {
                    td->text = strdup(td_text);
                }
                td_text = NULL;
            }
            step = step_get_left;
        }
    } /* for */
    return table;

}


